package com.hyacinth.lotterysystem.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hyacinth.lotterysystem.common.constant.Constants;
import com.hyacinth.lotterysystem.common.errocde.ServiceErrorCodeConstants;
import com.hyacinth.lotterysystem.common.exception.ServiceException;
import com.hyacinth.lotterysystem.common.utils.JacksonUtil;
import com.hyacinth.lotterysystem.common.utils.RedisUtil;
import com.hyacinth.lotterysystem.dao.entity.*;
import com.hyacinth.lotterysystem.dao.mapper.*;
import com.hyacinth.lotterysystem.dto.param.*;
import com.hyacinth.lotterysystem.dto.req.ActivityListReq;
import com.hyacinth.lotterysystem.dto.req.CreateActivityReq;
import com.hyacinth.lotterysystem.dto.resp.ActivityDetailCacheResp;
import com.hyacinth.lotterysystem.dto.resp.ActivityDetailResp;
import com.hyacinth.lotterysystem.dto.resp.ActivityListResp;
import com.hyacinth.lotterysystem.dto.resp.CreateActivityResp;
import com.hyacinth.lotterysystem.service.ActivityPrizeService;
import com.hyacinth.lotterysystem.service.ActivityService;
import com.hyacinth.lotterysystem.service.ActivityUserService;
import com.hyacinth.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.hyacinth.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import com.hyacinth.lotterysystem.service.enums.ActivityStatusEnum;
import com.hyacinth.lotterysystem.service.enums.ActivityUserStatusEnum;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;

/**
 * @Author: Yun
 * @Date: 2025/10/4
 */
@Service
public class ActivityServiceImpl extends ServiceImpl<ActivityMapper, ActivityDO> implements ActivityService {
    private static final Logger logger = LoggerFactory.getLogger(ActivityServiceImpl.class);
    @Resource
    private UserMapper userMapper;
    @Resource
    private PrizeMapper prizeMapper;
    @Resource
    private ActivityMapper activityMapper;
    @Resource
    private ActivityPrizeService activityPrizeService;
    @Resource
    private ActivityUserService activityUserService;
    @Resource
    private RedisUtil redisUtil;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private ActivityUserMapper activityUserMapper;

    @Override
    @Transactional
    public CreateActivityResp createActivity(CreateActivityReq param) {
        // 校验活动信息是否正确
        checkActivityInfo(param);
        // 保存活动信息
        ActivityDO activityDO = new ActivityDO();
        BeanUtils.copyProperties(param, activityDO);
        activityDO.setStatus(ActivityStatusEnum.RUNNING);
        activityMapper.insert(activityDO);
        Long activityId = activityDO.getId();
        // 保存活动关联的奖品信息
        List<CreateActivityPrizeParam> avtityPrizeList = param.getActivityPrizeList();
        List<ActivityPrizeDO> activityPrizeDOList = avtityPrizeList.stream().
                map(activityPrizeParam -> {
                    ActivityPrizeDO activityPrizeDO = new ActivityPrizeDO();
                    BeanUtils.copyProperties(activityPrizeParam, activityPrizeDO);
                    activityPrizeDO.setActivityId(activityId);
                    activityPrizeDO.setStatus(ActivityPrizeStatusEnum.INIT.name());
                    return activityPrizeDO;
                }).toList();
        activityPrizeService.saveBatch(activityPrizeDOList);

        // 保存活动关联人员信息
        List<CreateActivityUserParam> userParamList = param.getActivityUserList();
        List<ActivityUserDO> activityUserDOList = userParamList.stream()
                .map(userParam -> {
                    ActivityUserDO activityUserDO = new ActivityUserDO();
                    BeanUtils.copyProperties(userParam, activityUserDO);
                    activityUserDO.setActivityId(activityId);
                    activityUserDO.setStatus(ActivityUserStatusEnum.INIT.name());
                    return activityUserDO;
                }).toList();
        activityUserService.saveBatch(activityUserDOList);
        // 整合完整的活动信息 存放redis中
        // 获取奖品的id列表
        List<Long> prizeIds = avtityPrizeList.stream()
                .map(CreateActivityPrizeParam::getPrizeId)
                .distinct()
                .toList();
        LambdaQueryWrapper<PrizeDO> prizeDOLambdaQueryWrapper = Wrappers.lambdaQuery(PrizeDO.class)
                .in(PrizeDO::getId, prizeIds);

        List<PrizeDO> prizeDOList = prizeMapper.selectList(prizeDOLambdaQueryWrapper);
        ActivityDetailCacheResp activityDetailCacheResp = convertToActivityDetailCacheResp(activityDO, activityPrizeDOList, activityUserDOList, prizeDOList);
        activityDetailCacheResp.setActivityId(activityId);
        cacheActivity(activityDetailCacheResp);

        CreateActivityResp createActivityResp = new CreateActivityResp();
        createActivityResp.setId(activityId);
        return createActivityResp;
    }

    @Override
    public IPage<ActivityListResp> selectActivityList(ActivityListReq activityListReq) {
        if (activityListReq == null)
            activityListReq = new ActivityListReq();
        Page<ActivityDO> activityDOPage = new Page<>(activityListReq.getCurrentPage(), activityListReq.getPageSize());
        LambdaQueryWrapper<ActivityDO> lambdaQueryWrapper = Wrappers.lambdaQuery(ActivityDO.class)
                .orderByDesc(ActivityDO::getId);
        activityDOPage = activityMapper.selectPage(activityDOPage, lambdaQueryWrapper);
        return activityDOPage.convert(activityDO -> {
            ActivityListResp activityListResp = new ActivityListResp();
            BeanUtils.copyProperties(activityDO, activityListResp);
            activityListResp.setValid(activityDO.valid());
            return activityListResp;
        });
    }

    @Override
    public ActivityDetailResp selectByActivityId(Long activityId) {
        if (activityId == null) {
            logger.warn("查询活动详情失败,activityId为null");
            return null;
        }
        // 查询redis
        ActivityDetailCacheResp activityDetailCacheResp = getActivityFromCache(activityId);
        // 如果没查到查询数据库,查询完成之后再放到redis中
        if (activityDetailCacheResp == null) {
            // 查询活动表
            ActivityDO activityDO = activityMapper.selectById(activityId);
            // 活动奖品表
            List<ActivityPrizeDO> activityPrizeDOList = activityPrizeMapper.selectByActivityId(activityId);
            // 活动人员表
            List<ActivityUserDO> activityUserDOList = activityUserMapper.selectByActivityId(activityId);
            if (activityDO == null || activityPrizeDOList == null || activityUserDOList == null) {
                logger.warn("查询数据库活动详情为空");
                return null;
            }
            // 奖品表
            List<Long> prizeIds = activityPrizeDOList.stream()
                    .map(ActivityPrizeDO::getPrizeId)
                    .toList();
            List<PrizeDO> prizeDOList = prizeMapper.selectBatchIds(prizeIds);
            activityDetailCacheResp = convertToActivityDetailCacheResp(activityDO, activityPrizeDOList, activityUserDOList, prizeDOList);
            cacheActivity(activityDetailCacheResp);
        }

        // 转换
        ActivityDetailResp activityDetailResp = new ActivityDetailResp();
        activityDetailResp.setValid(activityDetailCacheResp.valid());
        BeanUtils.copyProperties(activityDetailCacheResp, activityDetailResp);

        // 设置 ActivityDetailResp 中的 List<ActivityDetailPrizeParam> prizeParamList;
        List<ActivityDetailCachePrizeParam> prizeParamList = activityDetailCacheResp.getPrizeParamList();
        activityDetailResp.setPrizeParamList(prizeParamList.stream()
                .sorted(Comparator.comparingInt(prizeParam -> prizeParam.getPrizeTiers().getCode()))
                .map(prizeParam -> {
                    ActivityDetailPrizeParam activityDetailPrizeParam = new ActivityDetailPrizeParam();
                    BeanUtils.copyProperties(prizeParam, activityDetailPrizeParam);
                    activityDetailPrizeParam.setPrizeTiers(prizeParam.getPrizeTiers().getMessage());
                    activityDetailPrizeParam.setValid(prizeParam.valid());
                    return activityDetailPrizeParam;
                }).toList()
        );
        // 设置 ActivityDetailResp 中的 List<ActivityDetailUserParam> userParamList;
        List<ActivityDetailCacheUserParam> userParamList = activityDetailCacheResp.getUserParamList();
        activityDetailResp.setUserParamList(userParamList.stream()
                .map(userParam -> {
                    ActivityDetailUserParam activityDetailUserParam = new ActivityDetailUserParam();
                    BeanUtils.copyProperties(userParam, activityDetailUserParam);
                    activityDetailUserParam.setValid(userParam.valid());
                    return activityDetailUserParam;
                }).toList()
        );


        return activityDetailResp;
    }

    @Override
    public void cacheActivity(Long activityId) {
        if (activityId == null) {
            logger.warn("缓存活动的id为空");
            throw new ServiceException(ServiceErrorCodeConstants.CACHE_ACTIVITY_ID_IS_EMPTY);
        }
        ActivityDO activityDO = activityMapper.selectById(activityId);
        if (activityDO == null) {
            logger.error("缓存的活动id错误");
            throw new ServiceException(ServiceErrorCodeConstants.CACHE_ACTIVITY_ID_IS_ERROR);
        }
        List<ActivityPrizeDO> activityPrizeDOList = activityPrizeMapper.selectByActivityId(activityId);
        List<ActivityUserDO> activityUserDOList = activityUserMapper.selectByActivityId(activityId);
        List<Long> prizeIds = activityPrizeDOList.stream()
                .map(ActivityPrizeDO::getPrizeId)
                .toList();
        List<PrizeDO> prizeDOList = prizeMapper.selectBatchIds(prizeIds);

        ActivityDetailCacheResp activityDetailCacheResp = convertToActivityDetailCacheResp(activityDO, activityPrizeDOList, activityUserDOList, prizeDOList);
        activityDetailCacheResp.setActivityId(activityId);
        cacheActivity(activityDetailCacheResp);
    }

    /**
     * 缓存活动信息
     *
     * @param activityDetailCacheResp
     */
    private void cacheActivity(ActivityDetailCacheResp activityDetailCacheResp) {
        if (null == activityDetailCacheResp || null == activityDetailCacheResp.getActivityId()) {
            logger.warn("缓存活动信息不存在,activityDetailCacheResp: {}", activityDetailCacheResp);
            return;
        }
        try {
            redisUtil.set(Constants.REDIS_KEY_ACTIVITY_PREFIX + activityDetailCacheResp.getActivityId(), JacksonUtil.writeValueAsString(activityDetailCacheResp), Constants.ACTIVITY_TIME_OUT);
        } catch (Exception e) {
            logger.error("redis 活动信息缓存异常activityDetailResp: {}", JacksonUtil.writeValueAsString(activityDetailCacheResp), e);
        }
    }

    private ActivityDetailCacheResp getActivityFromCache(Long activityId) {
        try {
            String str = redisUtil.get(Constants.REDIS_KEY_ACTIVITY_PREFIX + activityId);
            if (!StringUtils.hasText(str)) {
                logger.info("redis 获取活动信息为空, key = {}", Constants.REDIS_KEY_ACTIVITY_PREFIX + activityId);
                return null;
            }
            return JacksonUtil.readValue(str, ActivityDetailCacheResp.class);
        } catch (Exception e) {
            logger.error("redis 获取活动信息异常, key = {}", Constants.REDIS_KEY_ACTIVITY_PREFIX + activityId, e);
            return null;
        }
    }

    private ActivityDetailCacheResp convertToActivityDetailCacheResp(ActivityDO activityDO, List<ActivityPrizeDO> activityPrizeDOList, List<ActivityUserDO> activityUserDOList, List<PrizeDO> prizeDOList) {
        ActivityDetailCacheResp activityDetailCacheResp = new ActivityDetailCacheResp();
        BeanUtils.copyProperties(activityDO, activityDetailCacheResp);
        activityDetailCacheResp.setStatus(activityDO.getStatus());
        // 设置 ActivityDetailCacheResp 中的 List<ActivityDetailCachePrizeParam> prizeParamList
        List<ActivityDetailCachePrizeParam> activityDetailCachePrizeParams = activityPrizeDOList.stream()
                .map(activityPrizeDO -> {
                    ActivityDetailCachePrizeParam detailPrizeParam = new ActivityDetailCachePrizeParam();
                    Optional<PrizeDO> optionalPrizeDO = prizeDOList.stream().filter(prizeDO ->
                                    prizeDO.getId().equals(activityPrizeDO.getPrizeId()))
                            .findFirst();
                    optionalPrizeDO.ifPresent(prizeDO -> {
                        BeanUtils.copyProperties(prizeDO, detailPrizeParam);
                    });
                    detailPrizeParam.setPrizeId(activityPrizeDO.getPrizeId());
                    detailPrizeParam.setPrizeAmount(activityPrizeDO.getPrizeAmount());
                    detailPrizeParam.setPrizeTiers(ActivityPrizeTiersEnum.forName(activityPrizeDO.getPrizeTiers()));
                    detailPrizeParam.setStatus(ActivityPrizeStatusEnum.forName(activityPrizeDO.getStatus()));
                    return detailPrizeParam;
                }).toList();
        activityDetailCacheResp.setPrizeParamList(activityDetailCachePrizeParams);

        // 设置 ActivityDetailCacheResp 中的 List<ActivityDetailCacheUserParam> userParamList
        List<ActivityDetailCacheUserParam> userParamList = activityUserDOList.stream().map(activityUserDO -> {
            ActivityDetailCacheUserParam activityDetailCacheUserParam = new ActivityDetailCacheUserParam();
            BeanUtils.copyProperties(activityUserDO, activityDetailCacheUserParam);
            activityDetailCacheUserParam.setStatus(ActivityUserStatusEnum.forName(activityUserDO.getStatus()));
            return activityDetailCacheUserParam;
        }).toList();
        activityDetailCacheResp.setUserParamList(userParamList);
        return activityDetailCacheResp;
    }

    private void checkActivityInfo(CreateActivityReq param) {
        if (param == null)
            throw new ServiceException(ServiceErrorCodeConstants.CREATE_ACTIVITY_IS_EMPTY);

        // 人员数量 大于等于 奖品数量
        long prizeAmount = param.getActivityPrizeList().stream().mapToLong(CreateActivityPrizeParam::getPrizeAmount).sum();
        if (param.getActivityUserList().size() < prizeAmount)
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_GT_PEOPLE);

        // 检验奖品等级
        param.getActivityPrizeList().forEach(prize -> {
            if (null == ActivityPrizeTiersEnum.forName(prize.getPrizeTiers())) {
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_AMOUNT_ERROR);
            }
        });
        // 人员id在人员表中是否存在
        List<Long> userIds = param.getActivityUserList().stream()
                .map(CreateActivityUserParam::getUserId)
                .distinct()
                .toList();
        LambdaQueryWrapper<UserDO> userDOLambdaQueryWrapper = Wrappers.lambdaQuery(UserDO.class)
                .in(UserDO::getId, userIds);
        List<UserDO> userDOS = userMapper.selectList(userDOLambdaQueryWrapper);

        if (userDOS.size() < userIds.size())
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_USER_NOT_EXISTS);

        // 奖品id在奖品表中是否存在
        List<Long> prizeIds = param.getActivityPrizeList().stream()
                .map(CreateActivityPrizeParam::getPrizeId)
                .distinct()
                .toList();
        LambdaQueryWrapper<PrizeDO> prizeDOLambdaQueryWrapper = Wrappers.lambdaQuery(PrizeDO.class)
                .in(PrizeDO::getId, prizeIds);
        List<PrizeDO> prizeDOS = prizeMapper.selectList(prizeDOLambdaQueryWrapper);

        if (prizeDOS.size() < prizeIds.size())
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_NOT_EXISTS);

    }
}
